﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

namespace RSSReader
{
    class DateUtils
    {
        #region ParseRfc822Date(string date)
        /// <summary>
        /// Returns a System.DateTime structure by parsing the supplied RFC822 datetime string.
        /// </summary>
        /// <param name="date">RFC822 datetime to parse</param>
        /// <returns>DateTime</returns>
        public static DateTime ParseRfc822Date(string date)
        {
            //------------------------------------------------------------
            //    Local members
            //------------------------------------------------------------
            System.DateTime dateTime;
            int position;

            //------------------------------------------------------------
            //    Validate parameters
            //------------------------------------------------------------
            if (String.IsNullOrEmpty(date))
            {
                throw new ArgumentNullException("date");
            }

            //------------------------------------------------------------
            //    Initialize local members
            //------------------------------------------------------------
            position = date.LastIndexOf(" ");

            //------------------------------------------------------------
            //    Attempt to parse from string
            //------------------------------------------------------------
            try
            {
                dateTime = Convert.ToDateTime(date, DateTimeFormatInfo.InvariantInfo);

                if (date.Substring(position + 1) == "Z")
                {
                    dateTime = dateTime.ToUniversalTime();
                }
                else if (date.Substring(position + 1) == "GMT")
                {
                    dateTime = dateTime.ToUniversalTime();
                }

                //------------------------------------------------------------
                //    Return result
                //------------------------------------------------------------
                return dateTime;
            }
            catch (System.FormatException formatException)
            {
                System.Diagnostics.Trace.WriteLine(formatException.Message);
            }

            //------------------------------------------------------------
            //    Attempt to parse from string at alternate position
            //------------------------------------------------------------
            dateTime = Convert.ToDateTime(date.Substring(0, position), DateTimeFormatInfo.InvariantInfo);

            if (date[position + 1] == '+')
            {
                int hours = Convert.ToInt32(date.Substring(position + 2, 2), NumberFormatInfo.InvariantInfo);
                dateTime = dateTime.AddHours(-hours);
                int minutes = Convert.ToInt32(date.Substring(position + 4, 2), NumberFormatInfo.InvariantInfo);
                dateTime = dateTime.AddMinutes(-minutes);
            }
            else if (date[position + 1] == '-')
            {
                int hours = Convert.ToInt32(date.Substring(position + 2, 2), NumberFormatInfo.InvariantInfo);
                dateTime = dateTime.AddHours(hours);
                int minutes = Convert.ToInt32(date.Substring(position + 4, 2), NumberFormatInfo.InvariantInfo);
                dateTime = dateTime.AddMinutes(minutes);
            }
            else
            {
                //------------------------------------------------------------
                //    Return result
                //------------------------------------------------------------
                dateTime = ApplyDateTimeFormat(date.Substring(position + 1), dateTime);
            }

            return dateTime;
        }
        #endregion

        #region ApplyDateTimeFormat(string formatCode, DateTime dateTime)
        /// <summary>
        /// Private routine to add appropriate hours to DateTime based on supplied format code.
        /// </summary>
        /// <param name="formatCode">Code to use in determining hours to add.</param>
        /// <param name="dateTime">DateTime structure to modify.</param>
        /// <returns>DateTime structure modified based on format code.</returns>
        private static DateTime ApplyDateTimeFormat(string formatCode, DateTime dateTime)
        {
            //------------------------------------------------------------
            //    Local members
            //------------------------------------------------------------
            Dictionary<string, int> dictionary = new Dictionary<string, int>();
            DateTime result;

            //------------------------------------------------------------
            //    Attempt to add hours
            //------------------------------------------------------------
            try
            {
                //------------------------------------------------------------
                //    Set default result
                //------------------------------------------------------------
                result = dateTime;

                //------------------------------------------------------------
                //    Fill lookup dictionary
                //------------------------------------------------------------
                dictionary.Add("A", 1);
                dictionary.Add("B", 2);
                dictionary.Add("C", 3);
                dictionary.Add("D", 4);
                dictionary.Add("E", 5);
                dictionary.Add("F", 6);
                dictionary.Add("G", 7);
                dictionary.Add("H", 8);
                dictionary.Add("I", 9);
                dictionary.Add("K", 10);
                dictionary.Add("L", 11);
                dictionary.Add("M", 12);

                dictionary.Add("N", -1);
                dictionary.Add("O", -2);
                dictionary.Add("P", -3);
                dictionary.Add("Q", -4);
                dictionary.Add("R", -5);
                dictionary.Add("S", -6);
                dictionary.Add("T", -7);
                dictionary.Add("U", -8);
                dictionary.Add("V", -9);
                dictionary.Add("W", -10);
                dictionary.Add("X", -11);
                dictionary.Add("Y", -12);

                dictionary.Add("EST", 5);
                dictionary.Add("EDT", 4);

                dictionary.Add("CST", 6);
                dictionary.Add("CDT", 5);

                dictionary.Add("MST", 7);
                dictionary.Add("MDT", 6);

                dictionary.Add("PST", 8);
                dictionary.Add("PDT", 7);

                //------------------------------------------------------------
                //    Add hours for specified format code via lookup
                //------------------------------------------------------------
                result = dateTime.AddHours(dictionary[formatCode.ToUpperInvariant()]);
            }
            catch
            {
                //------------------------------------------------------------
                //    Rethrow exception
                //------------------------------------------------------------
                throw;
            }

            //------------------------------------------------------------
            //    Return formatted result
            //------------------------------------------------------------
            return result;
        }
        #endregion
    }
}
